﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.IO.Compression;

namespace JZipper
{
    class Program
    {
        static void Main(string[] args)
        {
            BoasVindas();

            Executar(args);

            Sair();
        }


        private static void BoasVindas()
        {
            Console.WriteLine("\r\nJZipper V0.1.6 2013.04");
            Console.WriteLine("por Jeudi Prando\r\n");
        }


        private static ZipConf GerarZipConf(string[] args)
        {
            ZipConf conf = new ZipConf();
            conf.ArquivoZip = args[1];
            Int32 lenCutIni = Environment.CurrentDirectory.Length + 1;
            conf.ListaArquivos = args.Skip(2).Select((a) =>
            {
                if (a.StartsWith(Environment.CurrentDirectory))
                { a = a.Substring(lenCutIni); }
                else { a = Path.GetFileName(a); }
                return a;
            });
            return conf;
        }

        private static void Executar(string[] args)
        {
            if (args == null || args.Count() < 3) { Help(); return; }

            ZipConf conf = GerarZipConf(args);

            switch (args[0])
            {
                case "Z": GerarZip(conf); break;
                case "X": ExtrairZip(args); break;
            }
        }


        private static void GerarZip(ZipConf conf)
        {
            Console.WriteLine("{0,5} : {1}", "Gerar", conf.NomeArquivoZip);
            Console.WriteLine("{0,5} : {1}\r\n", "em", conf.CaminhoArquivoZip);

            using (ZipArchive z = ZipFile.Open(conf.NomeArquivoZip, conf.ZipMode))
            { AdicionarArquivos(z, conf); } /// ZipArchive Dispose
        }

        private static void AdicionarArquivos(ZipArchive z, ZipConf conf)
        {
            Int32 total = conf.ListaArquivos.Count();
            Int32 atual = 0;

            foreach (String item in conf.ListaArquivos)
            {
                atual++;
                if (File.Exists(item))
                {
                    Console.WriteLine("{2,3:00}% {0,-11} {1}", "Adicionando", item, (atual * 100.00) / total);

                    if (conf.ZipMode == ZipArchiveMode.Update)
                    {
                        ZipArchiveEntry zae = z.Entries.Where((zf) => zf.Name == item).FirstOrDefault();
                        if (zae != null)
                        { zae.Delete(); }
                    }
                    z.CreateEntryFromFile(item, item, CompressionLevel.Optimal);
                }
                else
                { Console.WriteLine("{2,3:00}% {0,-11} {1}", "Não existe", item, (atual * 100.00) / total); }
            }
            Console.WriteLine();
        }


        private static void ExtrairZip(string[] args)
        {
            throw new NotImplementedException();
        }


        private static void Help()
        {
            Console.WriteLine("Gerar ou Extrair um arquivo compactado\r\n");

            Console.WriteLine("Sintaxe:\r\n");

            Console.WriteLine("jzipper Z|X c:\\caminho\\arquivo.zip arquivo1 [arquivo2 arquivo3 arquivoN]\r\n");

            Console.WriteLine("Z - Gerar um arquivo compactado");
            Console.WriteLine("X - Extrair um arquivo compactado\r\n");

            Console.WriteLine("c:\\caminho\\arquivo.zip - Caminho e nome do arquivo compactado\r\n");

            Console.WriteLine("arquivo1 - lista de arquivo para compactar ou extrair\r\n");
        }

        private static void Sair()
        {
#if DEBUG
            Console.WriteLine("\r\nPressione qualquer tecla para continuar...");
            Console.ReadKey();
#endif
        }

    }

    struct ZipConf
    {
        public String ArquivoZip;

        public String CaminhoArquivoZip
        {
            get
            {
                String caminho = Path.GetDirectoryName(this.ArquivoZip);
                if (String.IsNullOrWhiteSpace(caminho))
                { caminho = Environment.CurrentDirectory; }
                return caminho;
            }
        }
        public String NomeArquivoZip { get { return Path.GetFileName(this.ArquivoZip); } }

        public IEnumerable<String> ListaArquivos;

        private Boolean? _arquivoZipExiste;
        public Boolean ArquivoZipExiste
        {
            get
            {
                if (this._arquivoZipExiste == null)
                { this._arquivoZipExiste = File.Exists(ArquivoZip); }
                return Convert.ToBoolean(this._arquivoZipExiste);
            }
        }

        public ZipArchiveMode ZipMode
        {
            get
            {
                if (this.ArquivoZipExiste)
                { return ZipArchiveMode.Update; }
                else
                { return ZipArchiveMode.Create; }
            }
        }
    }
}
